import streamlit as st
import os
import subprocess
import platform

# ---------------------- 页面基础配置 ----------------------
st.set_page_config(
    page_title="Streamlit 应用中心",
    page_icon="📱",
    layout="wide"
)

# 隐藏顶部默认导航栏和页脚
hide_default_format = """
    <style>
    #MainMenu {visibility: hidden;}
    footer {visibility: hidden;}
    header {visibility: hidden;}
    .stButton>button {
        background-color: #2E86AB;
        color: white;
        border-radius: 4px;
        padding: 8px 20px;
    }
    .stButton>button:hover {
        background-color: #1E6091;
        color: white;
    }
    .app-card {
        border: 1px solid #e0e0e0;
        border-radius: 8px;
        padding: 20px;
        margin-bottom: 20px;
        box-shadow: 0 2px 5px rgba(0,0,0,0.05);
        transition: all 0.3s ease;
    }
    .app-card:hover {
        box-shadow: 0 5px 15px rgba(0,0,0,0.1);
        transform: translateY(-3px);
    }
    .app-category {
        font-size: 12px;
        color: #666;
        margin-top: 8px;
    }
    </style>
"""
st.markdown(hide_default_format, unsafe_allow_html=True)

# ---------------------- 辅助函数：获取Windows浏览器路径 ----------------------
def get_windows_browser_path():
    """获取Windows系统中常见浏览器的路径"""
    possible_paths = [
        # Edge浏览器
        "C:/Program Files (x86)/Microsoft/Edge/Application/msedge.exe",
        "C:/Program Files/Microsoft/Edge/Application/msedge.exe",
        # Chrome浏览器
        "C:/Program Files/Google/Chrome/Application/chrome.exe",
        "C:/Program Files (x86)/Google/Chrome/Application/chrome.exe",
        # Firefox浏览器
        "C:/Program Files/Mozilla Firefox/firefox.exe",
        "C:/Program Files (x86)/Mozilla Firefox/firefox.exe",
        # 系统默认浏览器调用
        "C:/Windows/explorer.exe"
    ]
    
    for path in possible_paths:
        # 转换为WSL格式路径进行检查
        if os.path.exists(path.replace("C:/", "/mnt/c/").replace("\\", "/")):
            return path
    return None


def start_app_and_open_browser(app_name, app_url, app_access_url):
    """启动应用并在浏览器中打开（优化WSL/Windows兼容性）"""
    try:
        # ---------------------- 1. 启动应用脚本（修复路径与端口） ----------------------
        if os.name == 'posix' and 'WSL_DISTRO_NAME' in os.environ:
            # WSL环境：处理Windows路径（如D:/xxx.bat）
            if app_url.startswith(('C:', 'D:', 'E:')):
                # 转换Windows路径为WSL格式（例：D:/a.bat → /mnt/d/a.bat）
                drive = app_url[0].lower()  # 提取盘符（D → d）
                wsl_script_path = app_url.replace(f"{app_url[0]}:/", f"/mnt/{drive}/").replace("\\", "/")
                # 用WSL的cmd.exe启动Windows批处理（确保脚本内指定端口）
                subprocess.Popen(
                    ['cmd.exe', '/c', wsl_script_path],  # 直接传转换后的路径
                    stdout=subprocess.PIPE, 
                    stderr=subprocess.PIPE,
                    shell=False
                )
            else:
                # WSL内部脚本（如.sh）：确保脚本内指定端口（例：streamlit run app.py --server.port 8508）
                subprocess.Popen(
                    ['bash', app_url],
                    stdout=subprocess.PIPE, 
                    stderr=subprocess.PIPE,
                    shell=False
                )
        elif os.name == 'nt':
            # 纯Windows环境：直接启动批处理
            os.startfile(app_url)
        else:
            # 其他Linux：赋予执行权限并启动
            os.system(f"chmod +x {app_url} && {app_url} &")
        
        # ---------------------- 2. 延长等待时间（确保应用启动） ----------------------
        import time
        time.sleep(5)  # 从3秒延长到5秒，适配Streamlit启动耗时
        
        # ---------------------- 3. 打开浏览器（简化逻辑，优先用系统默认） ----------------------
        if os.name == 'posix' and 'WSL_DISTRO_NAME' in os.environ:
            # WSL环境：优先用wslview（需安装wslu），其次用Windows默认浏览器
            try:
                # 方案1：用wslview（WSL官方推荐，自动调用Windows默认浏览器）
                subprocess.Popen(['wslview', app_access_url], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            except FileNotFoundError:
                # 方案2：若wslview未安装，直接调用Windows浏览器（无需手动找路径）
                subprocess.Popen(
                    ['cmd.exe', '/c', f'start {app_access_url}'],  # start命令调用Windows默认浏览器
                    stdout=subprocess.PIPE,
                    stderr=subprocess.PIPE
                )
        elif os.name == 'nt':
            # 纯Windows：用start命令确保调用默认浏览器（修复os.startfile可能的兼容性问题）
            os.system(f"start {app_access_url}")
        else:
            # 其他Linux：用xdg-open调用默认浏览器
            subprocess.Popen(['xdg-open', app_access_url])
            
        return True, f"正在启动 {app_name}... 请稍候（浏览器将自动打开）"
        
    except Exception as e:
        return False, f"启动失败: {str(e)}（请检查脚本路径和端口是否正确）"

st.markdown(
    """
    <div style='text-align: center; margin-bottom: 30px;'>
        <h1 style='color: #2E86AB; font-weight: bold;'>📱 Streamlit 应用中心</h1>
        <p style='color: #666; font-size: 16px;'>点击按钮启动对应应用，自动加载专属运行环境</p>
    </div>
    """,
    unsafe_allow_html=True
)

APPS = {
    "Kill all Port except 8501": {
        "url": "main-entrence/stop_streamlit.sh",
        "icon": "🔌",  # 端口相关，使用插头图标
        "category": "辅助工具",
        "desc": "used for quick reset",
        "port": 8888
    },
    "高斯计算输入文件生成工具": {
        "url": "/home/pmo/linhan/main-entrence/GuassianInputFileGenerator.sh",
        "icon": "📝",  # 文件生成，使用文档图标
        "category": "特征计算",
        "desc": "快速计算化合物构型、根据计算任务生产高斯计算输入文件",
        "port": 8511
    },
    "化合物原子序号查看器": {
        "url": "/home/pmo/linhan/main-entrence/AtomNumberIdentifier.sh",
        "icon": "⚛️",  # 原子相关，使用原子图标
        "category": "特征计算",
        "desc": "以3d模型查看原子序号，根据指定顺序记录指定原子序号",
        "port": 8502
    },
    "高斯计算特征提取器": {
        "url": "/home/pmo/linhan/main-entrence/DescriptorExtractor.sh",
        "icon": "🔍",  # 提取特征，使用搜索/提取图标
        "category": "特征计算",
        "desc": "根据高斯输出文件，和原子序号文件，输出化合物特征",
        "port": 8503
    },
    "Fingerprints计算器": {
        "url": "/home/pmo/linhan/main-entrence/FingerprintEncoding.sh",
        "icon": "🔏",  # 指纹相关，使用锁/指纹图标
        "category": "特征计算",
        "desc": "支持drfp, MACCS, Morgan等fingerprints",
        "port": 8504
    },
    "rxnFP计算器": {
        "url": "/home/pmo/linhan/main-entrence/rxnfp_Chinese.sh",
        "icon": "🔄",  # 反应相关，使用循环/反应图标
        "category": "特征计算",
        "desc": "根据reaction smiles生成 rxn fingerprints",
        "port": 8505
    },
    "Reaction Smiles生成器": {
        "url": "/home/pmo/linhan/main-entrence/reactionsmiles.sh",
        "icon": "⚗️",  # 化学反应，使用烧杯图标
        "category": "辅助工具",
        "desc": "根据输入smiles列表，生产反应smiles",
        "port": 8506
    },
    "特征合并工具": {
        "url": "/home/pmo/linhan/main-entrence/df_merge.sh",
        "icon": "🧩",  # 合并功能，使用拼图图标
        "category": "辅助工具",
        "desc": "根据输入特征文件，合并特征",
        "port": 8507
    },
    "BNN模型": {
        "url": "/home/pmo/linhan/main-entrence/bnn.sh",
        "icon": "🧠",  # 神经网络，使用大脑图标
        "category": "模型搭建",
        "desc": "支持BNN-NUTS, BNN-SVI等模型",
        "port": 8508
    },
    "EDBO模型": {
        "url": "/home/pmo/linhan/main-entrence/edbo.sh",
        "icon": "📈",  # 优化模型，使用上升图表
        "category": "模型搭建",
        "desc": "基于EDBO进行自动优化",
        "port": 8509
    },
    "Single Threshold分析器": {
        "url": "/home/pmo/linhan/main-entrence/SingleThresholdAnalysis.sh",
        "icon": "📊",  # 数据分析，使用图表图标
        "category": "分析工具",
        "desc": "基于决策树的单一阈值分析",
        "port": 8510
    },
    "Scikit_Streamlit": {
        "url": "/home/pmo/linhan/main-entrence/sklearn_streamlit.sh",
        "icon": "🔬",  # 数据分析，使用图表图标
        "category": "模型搭建",
        "desc": "可以用于搭建scikit支持的主要模型，包括回归、分类、降维和聚类",
        "port": 8512
    },
    "数据增强": {
        "url": "/home/pmo/linhan/main-entrence/augmentation.sh",
        "icon": "🔢",  
        "category": "辅助工具",
        "desc": "使用高斯分布对回归类样本进行扩充",
        "port": 8513
    },
    "化学空间定义": {
        "url": "/home/pmo/linhan/main-entrence/chemicalspace.sh",
        "icon": "🧪",  
        "category": "辅助工具",
        "desc": "用于快速定义出广阔化学空间，可以包括非连续变量和连续变量，可将该空间用于BO优化。",
        "port": 8514
    }
}

# APPS = {
#     "Kill all Ports except 8501": {
#         "url": "main-entrence/stop_streamlit.sh",
#         "icon": "🔌",  # Port-related, using plug icon
#         "category": "Auxiliary Tools",
#         "desc": "used for quick reset",
#         "port": 8888
#     },
#     "Gaussian Calculation Input File Generator": {
#         "url": "/home/pmo/linhan/main-entrence/GuassianInputFileGenerator.sh",
#         "icon": "📝",  # File generation, using document icon
#         "category": "Feature Calculation",
#         "desc": "Quickly calculate compound configurations and generate Gaussian calculation input files based on calculation tasks",
#         "port": 8511
#     },
#     "Compound Atom Number Viewer": {
#         "url": "/home/pmo/linhan/main-entrence/AtomNumberIdentifier.sh",
#         "icon": "⚛️",  # Atom-related, using atom icon
#         "category": "Feature Calculation",
#         "desc": "View atomic numbers with 3D models and record specified atomic numbers in the specified order",
#         "port": 8502
#     },
#     "Gaussian Calculation Feature Extractor": {
#         "url": "/home/pmo/linhan/main-entrence/DescriptorExtractor.sh",
#         "icon": "🔍",  # Feature extraction, using search/extraction icon
#         "category": "Feature Calculation",
#         "desc": "Output compound features based on Gaussian output files and atomic number files",
#         "port": 8503
#     },
#     "Fingerprints Calculator": {
#         "url": "/home/pmo/linhan/main-entrence/FingerprintEncoding.sh",
#         "icon": "🔏",  # Fingerprint-related, using lock/fingerprint icon
#         "category": "Feature Calculation",
#         "desc": "Supports drfp, MACCS, Morgan, and other fingerprints",
#         "port": 8504
#     },
#     "rxnFP Calculator": {
#         "url": "/home/pmo/linhan/main-entrence/rxnfp_Chinese.sh",
#         "icon": "🔄",  # Reaction-related, using cycle/reaction icon
#         "category": "Feature Calculation",
#         "desc": "Generate rxnFP fingerprints based on reaction smiles",
#         "port": 8505
#     },
#     "Reaction Smiles Generator": {
#         "url": "/home/pmo/linhan/main-entrence/reactionsmiles.sh",
#         "icon": "⚗️",  # Chemical reaction, using beaker icon
#         "category": "Auxiliary Tools",
#         "desc": "Generate reaction smiles based on input smiles lists",
#         "port": 8506
#     },
#     "Feature Merging Tool": {
#         "url": "/home/pmo/linhan/main-entrence/df_merge.sh",
#         "icon": "🧩",  # Merging function, using puzzle icon
#         "category": "Auxiliary Tools",
#         "desc": "Merge features based on input files",
#         "port": 8507
#     },
#     "BNN Model": {
#         "url": "/home/pmo/linhan/main-entrence/bnn.sh",
#         "icon": "🧠",  # Neural network, using brain icon
#         "category": "Model Building",
#         "desc": "Supports models such as BNN-NUTS and BNN-SVI",
#         "port": 8508
#     },
#     "EDBO Model": {
#         "url": "/home/pmo/linhan/main-entrence/edbo.sh",
#         "icon": "📈",  # Optimization model, using rising chart icon
#         "category": "Model Building",
#         "desc": "Automatic optimization based on EDBO",
#         "port": 8509
#     },
#     "Single Threshold Analyzer": {
#         "url": "/home/pmo/linhan/main-entrence/SingleThresholdAnalysis.sh",
#         "icon": "📊",  # Data analysis, using chart icon
#         "category": "Analysis Tools",
#         "desc": "Single threshold analysis based on decision trees",
#         "port": 8510
#     },
#     "Scikit_Streamlit": {
#         "url": "/home/pmo/linhan/main-entrence/sklearn_streamlit.sh",
#         "icon": "🔬",  # Data analysis, using laboratory icon
#         "category": "Model Building",
#         "desc": "Can be used to build major models supported by scikit, including regression, classification, dimensionality reduction, and clustering",
#         "port": 8512
#     },
#     "Data Augmentation": {
#         "url": "/home/pmo/linhan/main-entrence/augmentation.sh",
#         "icon": "🔢",  
#         "category": "Auxiliary Tools",
#         "desc": "Augment regression samples using Gaussian distribution",
#         "port": 8513
#     },
#     "Chemical Space Definition": {
#         "url": "/home/pmo/linhan/main-entrence/chemicalspace.sh",
#         "icon": "🧪",  
#         "category": "Auxiliary Tools",
#         "desc": "Used to quickly define a broad chemical space, which can include discontinuous and continuous variables, and can be used for BO optimization",
#         "port": 8514
#     }
# }

# ---------------------- 分类筛选 ----------------------
categories = list(set(app["category"] for app in APPS.values()))
selected_category = st.selectbox(
    "🔍 按分类筛选",
    options=["全部"] + categories,
    index=0,
    key="category_filter"
)

# ---------------------- 卡片式应用布局 ----------------------
cols_per_row = 3  # 每行显示3个卡片
filtered_apps = [
    (name, info) for name, info in APPS.items()
    if selected_category == "全部" or info["category"] == selected_category
]

# 生成卡片
for i in range(0, len(filtered_apps), cols_per_row):
    row = st.columns(cols_per_row, gap="medium")
    for j in range(cols_per_row):
        if i + j < len(filtered_apps):
            app_name, app_info = filtered_apps[i + j]
            with row[j]:
                # 卡片内容
                st.markdown(
                    f"""
                    <div class="app-card">
                        <h3 style="margin-top: 0;">{app_info['icon']}  {app_name}</h3>
                        <p style="color: #666; font-size: 14px;">{app_info['desc']}</p>
                    </div>
                    """,
                    unsafe_allow_html=True
                )
                
                # 启动按钮
                if st.button("🚀 启动应用", key=f"btn_{app_name}"):
                    if app_name == "Kill all Port except 8501":
                        if os.name == 'posix' and 'WSL_DISTRO_NAME' in os.environ:
                            # WSL环境：处理Windows路径（如D:/xxx.bat）
                            if app_info["url"].startswith(('C:', 'D:', 'E:')):
                                # 转换Windows路径为WSL格式（例：D:/a.bat → /mnt/d/a.bat）
                                drive = app_info["url"][0].lower()  # 提取盘符（D → d）
                                wsl_script_path = app_info["url"].replace(f"{app_info['url'][0]}:/", f"/mnt/{drive}/").replace("\\", "/")
                                # 用WSL的cmd.exe启动Windows批处理（确保脚本内指定端口）
                                subprocess.Popen(
                                    ['cmd.exe', '/c', wsl_script_path],  # 直接传转换后的路径
                                    stdout=subprocess.PIPE, 
                                    stderr=subprocess.PIPE,
                                    shell=False
                                )
                                st.success("CLose all ports successfully")
                            else:
                                # WSL内部脚本（如.sh）：确保脚本内指定端口（例：streamlit run app.py --server.port 8508）
                                subprocess.Popen(
                                    ['bash', app_info["url"]],
                                    stdout=subprocess.PIPE, 
                                    stderr=subprocess.PIPE,
                                    shell=False
                                )
                                st.success("CLose all ports successfully")
                        elif os.name == 'nt':
                            # 纯Windows环境：直接启动批处理
                            os.startfile(app_info["url"])
                            st.success("CLose all ports successfully")
                        else:
                            # 其他Linux：赋予执行权限并启动
                            os.system(f"chmod +x {app_info['url']} && {app_info['url']} &")
                            st.success("CLose all ports successfully")
                    else:
                        # 构建应用访问URL（使用每个应用的专属端口）
                        app_access_url = f"http://localhost:{app_info['port']}"
                        
                        # 启动应用并打开浏览器
                        success, message = start_app_and_open_browser(
                            app_name, 
                            app_info["url"],
                            app_access_url
                        )
                        
                        if success:
                            st.success(message)
                            # 显示应用URL，方便手动访问
                            st.info(f"应用地址: {app_access_url}")
                        else:
                            st.error(message)
                            st.info(f"请手动访问: {app_access_url}")
                
                # 分类标签
                st.markdown(
                    f'<p class="app-category">分类：{app_info["category"]}</p>',
                    unsafe_allow_html=True
                )

# ---------------------- 底部提示 ----------------------
st.markdown(
    """
    <div style='text-align: center; margin-top: 40px; color: #666; font-size: 14px;'>
        <p>💡 提示：启动后请等待3-5秒，应用将自动在新窗口打开</p>
        <p>若未启动，请检查启动脚本路径是否正确或手动访问显示的应用地址</p>
    </div>
    """,
    unsafe_allow_html=True
)
    